home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / CW GUSI 1.6.4 / src / GUSIGlob.cp < prev    next >
Text File  |  1995-10-31  |  4KB  |  259 lines

  1. /*********************************************************************
  2. Project    :    GUSI                -    Grand Unified Socket Interface
  3. File        :    GUSIGlob.cp        -    Expand wildcard characters
  4. Author    :    Matthias Neeracher <neeri@iis.ethz.ch>
  5. Language    :    MPW C
  6.  
  7. $Log: GUSIFile.cp,v $
  8. *********************************************************************/
  9.  
  10. #include <ctype.h>
  11. #include <TextUtils.h>
  12.  
  13. #include "GUSIFile_P.h"
  14. #include "TFileGlob.h"
  15.  
  16. #pragma segment GUSI
  17.  
  18. /* Slice up and count segments. To deal with aliases, "::"s actually
  19.    count as an empty segment
  20. */
  21.  
  22. static int SliceSegments(char * pattern)
  23. {
  24.     int         segments = 1;
  25.     
  26.     for (; *pattern; ++pattern)
  27.         if (*pattern == ':') {
  28.             *pattern = 0;
  29.             
  30.             if (pattern[1])
  31.                 ++segments;
  32.         }
  33.         
  34.     return segments;
  35. }
  36.  
  37. static Boolean HasWildCards(char * pattern)
  38. {
  39.     for (;;) {
  40.         switch (*pattern) {
  41.         case '?':
  42.         case '*':
  43.         case '≈':
  44.             return true;
  45.         case '\\':
  46.         case '∂':
  47.             if (*++pattern)
  48.                 break;
  49.             // Else fall through
  50.         case 0:
  51.             return false;
  52.         default:
  53.             break;
  54.         }
  55.         ++pattern;
  56.     }
  57.     
  58.     return false;
  59. }
  60.  
  61. TFileGlob::TFileGlob(const char * pattern, const TFileSpec * startDir)
  62.     : TFileSpec(), patBuf(nil), track(nil)
  63. {
  64.     if (!*pattern)
  65.         error = bdNamErr;
  66.     else if (*pattern != ':' && strchr(pattern, ':'))  // full path pattern
  67.         Root();
  68.     else if (startDir)
  69.         *(TFileSpec *)this = *startDir;
  70.     else 
  71.         Default();
  72.     
  73.     if (*pattern == ':') {
  74.         ++pattern;
  75.         
  76.         if (!*pattern) {    // Very special case ":"
  77.             segments = 0;
  78.             valid     = true;
  79.             
  80.             return;
  81.         }
  82.     }
  83.             
  84.     int patlen = strlen(pattern);
  85.     
  86.     if (!(valid = !error) || !(patBuf = new char[patlen+1]))
  87.         return;
  88.     
  89.     memcpy(patBuf, pattern, patlen+1);
  90.     
  91.     UppercaseText(patBuf, patlen, smSystemScript);
  92.     
  93.     int segCount = SliceSegments(patBuf);
  94.     
  95.     if (segCount > 127) {
  96.         error = bdNamErr;
  97.         
  98.         return;
  99.     }
  100.     
  101.     if (!(track = new BackTrack[segCount]))
  102.         return;
  103.         
  104.     segments = segCount;
  105.     char * patSeg     = patBuf;
  106.     
  107.     for (segCount = 0; segCount < segments; patSeg += strlen(patSeg)+1) {
  108.         track[segCount].index = HasWildCards(patSeg) ? 0 : -1;
  109.         track[segCount++].pattern = patSeg;
  110.     }
  111.     
  112.     // Volume names always have to be matched exhaustively
  113.     
  114.     if (IsRoot())
  115.         track[0].index = 0;
  116.         
  117.     valid = Next(track, segments, true);
  118. }
  119.  
  120. Boolean TFileGlob::Next()
  121. {
  122.     for (int depth = segments; depth--; )
  123.         if (valid = Next(track+depth, segments - depth))
  124.             return true;
  125.     
  126.     return valid = false;
  127. }
  128.  
  129. static Boolean MatchName(const char * name, const char * pattern, int nameLen)
  130. {
  131.     while (nameLen--) {
  132.         switch (*pattern) {
  133.         case '\\':
  134.         case '∂':
  135.             if (!*++pattern)
  136.                 --pattern;        // special case at end of pattern
  137.             // Fall through
  138.         default:
  139.             if (toupper(*name) != *pattern)
  140.                 return false;
  141.             // Fall through
  142.         case '?':
  143.             ++name;
  144.             ++pattern;
  145.             
  146.             break;
  147.         case '*':
  148.         case '≈':
  149.             while (!MatchName(name, pattern+1, nameLen+1)) {
  150.                 if (nameLen-- < 0)
  151.                     return false;    // "a", "*b"
  152.                 ++name;                // "ba", "*a"  or "ba", "*b"
  153.             }
  154.             return true;             // "a", "*a"
  155.         }
  156.     }
  157.  
  158.     while (*pattern)
  159.         switch (*pattern) {
  160.         case '*':
  161.         case '≈':
  162.             ++pattern;
  163.             break;
  164.         default:
  165.             return false;
  166.         }
  167.         
  168.     return true;
  169. }
  170.  
  171. Boolean TFileGlob::Next(BackTrack * track, int depth, Boolean init)
  172. {
  173.     if (!depth) {
  174.         if (!Exists())
  175.             return false;
  176.         Bless();
  177.         
  178.         return true;
  179.     }
  180.     
  181.     if (track->index == -1) {    // Exact match
  182.         if (!init)            // Won't match again
  183.             return false;
  184.         if (!*track->pattern)
  185.             --*this;
  186.         else
  187.             *this += track->pattern;
  188.         
  189.         return Error() ? false : Next(track+1, depth - 1, true);
  190.     }
  191.     
  192.     if (init) {
  193.         *this += "";
  194.         
  195.         if (Error())
  196.             return false;
  197.         
  198.         track->index    =    0;
  199.         track->vRefNum    =    vRefNum;
  200.         track->parID    =  parID;
  201.     }
  202.     
  203.     for (;;) {
  204.         vRefNum = track->vRefNum;
  205.         parID   = track->parID;
  206.         
  207.         *(TFileSpec *)this = (*this)[++track->index];
  208.         
  209.         if (Error())
  210.             break;
  211.  
  212.         static char    uprName[64];
  213.  
  214.         memcpy(uprName, name+1, *name);
  215.         UppercaseText(uprName, *name, smSystemScript);
  216.                 
  217.         if (!MatchName((char *)name+1, track->pattern, *name))
  218.             continue;
  219.         
  220.         if (Next(track+1, depth - 1, true))
  221.             return true;
  222.     }
  223.     
  224.     return false;
  225. }
  226.  
  227. // C glue
  228.  
  229. FileGlobRef NewFileGlob(const char * pattern)
  230. {
  231.     FileGlobRef    glob = new TFileGlob(pattern);
  232.     
  233.     if (!glob->Error())
  234.         return glob;
  235.     
  236.     delete glob;
  237.     
  238.     return nil;
  239. }
  240.  
  241. Boolean NextFileGlob(FileGlobRef glob)
  242. {
  243.     return glob->Next();
  244. }
  245.  
  246. Boolean FileGlob2FSSpec(FileGlobRef glob, FSSpec * spec)
  247. {
  248.     if (glob->Valid())
  249.         *spec = *(FSSpec *) glob;
  250.         
  251.     return glob->Valid();
  252. }
  253.  
  254. void DisposeFileGlob(FileGlobRef glob)
  255. {
  256.     delete glob;
  257. }
  258.  
  259.